package com.yy.util.http;

import android.util.Log;
import android.util.SparseArray;

import org.apache.http.HttpStatus;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

/**
 * Created by zhangly on 2015/4/17.
 */
public class AppHttpUtil {

    private static final String TAG = AppHttpUtil.class.getSimpleName();

    public static final String PNG_URL = "http://upload.hifi33.com/images/201003/201003152325309954.jpg";

    private final static int RECONNECT = 3;
    private final static int REQ_MODE_HTTP = 0;
    private final static int REQ_MODE_HTTPS = 1;
    private final static int SC_OK = 200;

    private static SparseArray<String> cookiesCache = new SparseArray<String>();

    public SparseArray<InputStream> httpGet(String url) throws SocketTimeoutException, IOException {
        return startHttpConnection(url, "GET", null, REQ_MODE_HTTP, null);
    }

    public SparseArray<InputStream> httpGet(String url, Map<String, Object> params) throws SocketTimeoutException, IOException {
        return startHttpConnection(url, "GET", params, REQ_MODE_HTTP, null);
    }

    public SparseArray<InputStream> httpsGet(String url, InputStream cerFile) throws SocketTimeoutException, IOException {
        return startHttpConnection(url, "GET", null, REQ_MODE_HTTPS, cerFile);
    }

    public SparseArray<InputStream> httpsGet(String url, Map<String, Object> params, InputStream cerFile) throws SocketTimeoutException, IOException {
        return startHttpConnection(url, "GET", params, REQ_MODE_HTTPS, cerFile);
    }


    public SparseArray<InputStream> httpPost(String url, Map<String, Object> params) throws SocketTimeoutException, IOException {
        return startHttpConnection(url, "POST", params, REQ_MODE_HTTP, null);
    }

    public SparseArray<InputStream> httpsPost(String url, Map<String, Object> params, InputStream cerFile) throws SocketTimeoutException, IOException {
        return startHttpConnection(url, "POST", params, REQ_MODE_HTTPS, cerFile);
    }

    public boolean waitReconnect(int reconnectIndex) {
        if (reconnectIndex < RECONNECT) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return true;
        }
        return false;
    }

    public String makeUrl(String url, Map<String, Object> params) {
        StringBuilder sbUrl = new StringBuilder(url);
        if (params != null && !params.isEmpty()) {
            if (!url.contains("?")) {
                sbUrl.append('?');
            }
            for (String name : params.keySet()) {
                sbUrl.append('&');
                sbUrl.append(name);
                sbUrl.append('=');
                sbUrl.append(String.valueOf(params.get(name)));
                //不做URLEncoder处理
                //url.append(URLEncoder.encode(String.valueOf(params.get(name)), UTF_8));
            }
        }
        return sbUrl.toString().replace("?&", "?");
    }

    public byte[] makeParams2Byte(Map<String, Object> params) {
        StringBuilder sb = new StringBuilder();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, Object> itemParam : params.entrySet()) {
                sb.append(itemParam.getKey());
                sb.append("=");
                sb.append(itemParam.getValue());
                sb.append("&");
            }
            sb.deleteCharAt(sb.length() - 1);
            return sb.toString().getBytes();
        }
        return null;
    }

    /**
     * 保存cookie
     */
    public void saveCookie(HttpURLConnection connection) {
        StringBuilder sb = new StringBuilder();
        Map<String, List<String>> headers = connection.getHeaderFields();
        List<String> cookies = headers.get("Set-Cookie");
        if (cookies != null && cookies.size() > 0) {
            Iterator<String> iterator = cookies.iterator();
            while (iterator.hasNext()) {
                sb.append(iterator.next());
            }
            // AppException.log(TAG, "Cookie: " + sb.toString());
            cookiesCache.clear();
            cookiesCache.put(0, sb.toString());
            // cookieContiner.clear();
            // cookieContiner.put("Cookie", sb.toString());
        }
    }

    private HttpURLConnection openHttpURLConnection(String url, int reqMode, InputStream cerFile) {
        HttpURLConnection connection = null;
        try {
            switch (reqMode) {
                case REQ_MODE_HTTP:
                    connection = (HttpURLConnection) new URL(url).openConnection();
                    break;
                case REQ_MODE_HTTPS:
                    connection = getHttpsURLConnection(cerFile, url);
                    break;
            }
            connection.setDoInput(true);
            connection.setConnectTimeout(30000);
            connection.setRequestProperty("Accept-Charset", "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return connection;
    }

    private HttpURLConnection getHttpsURLConnection(InputStream cerFile, String url) {
        HttpsURLConnection connection = null;
        try {
            connection = (HttpsURLConnection) new URL(url).openConnection();
            CertificateFactory cerInstance = CertificateFactory.getInstance("X.509");
            Certificate certificate = cerInstance.generateCertificate(cerFile);

            KeyStore keyInstance = KeyStore.getInstance(KeyStore.getDefaultType());
            keyInstance.load(null, null);
            keyInstance.setCertificateEntry("cer", certificate);

            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory trustInstance = TrustManagerFactory.getInstance(algorithm);
            trustInstance.init(keyInstance);

            SSLContext sslInstance = SSLContext.getInstance("TLS");
            sslInstance.init(null, trustInstance.getTrustManagers(), null);
            connection.setSSLSocketFactory(sslInstance.getSocketFactory());
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return connection;
    }

    private SparseArray<InputStream> startHttpConnection(String url, String method,
                                                         Map<String, Object> params, int reqMode, InputStream cerFile)
            throws SocketTimeoutException, IOException {
        SparseArray<InputStream> inputStreamSparseArray = new SparseArray<InputStream>();
        InputStream inputStream = null;
        OutputStream outputStream = null;
        HttpURLConnection connection = null;
        int reqCode = 0;
        switch (method) {
            case "GET":
                connection = openHttpURLConnection(makeUrl(url, params), reqMode, cerFile);
                connection.setRequestMethod(method);
                connection.setRequestProperty("Cookie", cookiesCache.get(0));
                connection.connect();
                break;
            case "POST":
                connection = openHttpURLConnection(url, reqMode, cerFile);
                connection.setRequestMethod(method);
                connection.setRequestProperty("Cookie", cookiesCache.get(0));
                connection.setDoInput(true);
                connection.setDoOutput(true);
                outputStream = connection.getOutputStream();
                if (params != null) {
                    outputStream.write(makeParams2Byte(params));
                    outputStream.flush();
                    outputStream.close();
                    connection.connect();
                }
                break;
        }
        reqCode = connection.getResponseCode();
        if (reqCode == SC_OK) {
            saveCookie(connection);
            inputStreamSparseArray.put(connection.getContentLength(), connection.getInputStream());
        } else {
            inputStreamSparseArray.put(-1, IOHelper.toStream("error" + reqCode, "utf-8"));
        }
        return inputStreamSparseArray;
    }

}
